
package com.dkm.modules.wx.card.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dkm.commons.Response;
import com.dkm.constant.Constant;
import com.dkm.dataScope.DataScope;
import com.dkm.exception.ServiceException;
import com.dkm.modules.sys.user.mapper.CustomerMapper;
import com.dkm.modules.sys.user.model.Customer;
import com.dkm.modules.sys.user.model.CustomerBalance;
import com.dkm.modules.sys.user.model.RegisterUserResult;
import com.dkm.modules.sys.user.model.User;
import com.dkm.modules.sys.user.service.CustomerBalanceService;
import com.dkm.modules.wx.card.mapper.CardMapper;
import com.dkm.modules.wx.card.mapper.RechargeRecodMapper;
import com.dkm.modules.wx.card.model.Card;
import com.dkm.modules.wx.card.model.RechargeRecodPO;
import com.dkm.modules.wx.card.model.RechargeRecods;
import com.dkm.modules.wx.card.model.UseRecods;
import com.dkm.modules.wx.card.service.CardService;
import com.dkm.modules.wx.user.model.UserData;
import com.dkm.util.IdGen;
import com.dkm.util.StringUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName CardServiceImpl
 * @Description: 实现类
 * @Author yangbin
 * @Date 2019-09-13 12:50
 * @Version V1.0
 **/
@Slf4j
@Service
public class CardServiceImpl implements CardService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CardServiceImpl.class);

    @Autowired
    CustomerBalanceService customerBalanceService;

    @Autowired
    private CardMapper cardMapper;

    @Autowired
    CardService cardService;

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private RechargeRecodMapper rechargeRecodMapper;

    //后台可充值给IC电卡，挂失卡不可编辑。可编辑卡类型：未启动的和绑定后的卡。
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response rechargeCard(String cardNo, BigDecimal amount, User user) {
        if (org.apache.commons.lang3.StringUtils.isEmpty(cardNo)) {
            throw new ServiceException("卡号不能为空");
        }

        Card card = cardMapper.selectById(cardNo);
        this.validatedWhenRechargeCard(card, amount);

        // 更新卡余额
        this.updateAmountAndRecord(cardNo, amount, IdGen.uuid(), Constant.RECHARGE_RECOD_TYPE_SYSTEM, user);

        return Response.ok(cardMapper.selectById(cardNo));
    }

    private void validatedWhenRechargeCard(Card card, BigDecimal amount) {

        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("充值金额必须大于0");
        }

        // 见code表 parent_code=6 6001正常 6002挂失 6003未启用
        // 后台可充值给IC电卡，挂失卡不可编辑。可编辑卡类型：未启动的和绑定后的卡。

        if (card == null) {
            throw new ServiceException("卡号不存在");
        }
        if (null != card.getState() && Constant.CARD_STATE_LOSE.equals(card.getState())) {
            throw new ServiceException("挂失卡不可充值");
        }
        if (Constant.CARD_STATE_NORMAL.equals(card.getState())
                && null == card.getBindTime()) {
            throw new ServiceException("未绑定的卡不可充值");
        }
    }

    @Override
    public Response addCard(Card card) {
        /*判断卡号是否存在*/
        Card newCard = cardMapper.selectById(card.getCardNo());
        if (newCard != null) {
            return Response.error(-1, "卡号已存在");
        }
        //校验卡片信息
        if (!StringUtils.isNumeric(card.getCardNo()) || card.getCardNo().length() != 10) {
            return Response.error(-1, "卡号需为10位数字");
        }

        // 绑定用户
        this.bindCardCustomer(card, true);

        card.setCreateTime(new Date());
        cardMapper.insert(card);
        return Response.ok();
    }

    @Override
    public Response lossCard(String cardNo) {
        Card card = cardMapper.selectById(cardNo);
        //校验卡片
        if (card == null) {
            return Response.error(-1, "卡号不存在!");
        }
        if (StringUtils.equals(card.getState(), "6003")) {
            return Response.error(-5, "未启用卡不可挂失");
        }
        /*设置卡片状态为挂失*/
        card.setState("6002");
        /*设置更新时间*/
        card.setUpdateTime(new Date());
        cardMapper.updateById(card);

        return Response.ok();
    }


    /**
     * @描述 获取卡列表数据
     * @参数 [params 查询参数, page]
     * @返回值 com.baomidou.mybatisplus.core.metadata.IPage<com.dkm.modules.wx.card.model.Card>
     * @创建人 yangbin
     * @创建时间 2019/10/5
     */
    @Override
    @DataScope(alias = "a.operator")
    public IPage<Card> getCardList(Map<String, Object> params, Page<Card> page) {
        /*获取卡数据*/
        List<Card> cardList = cardMapper.getCardList(params, page);
        /*设置组装查询数据为page类型*/
        page.setRecords(cardList);
        return page;
    }


    @Override
    public IPage<UseRecods> getUseRecods(Page<UseRecods> page, String cardNo) {
        /*查询使用记录*/
        List<UseRecods> Recods = cardMapper.getUseRecods(page, cardNo);
        /*组装使用记录为page类型*/
        page.setRecords(Recods);
        return page;
    }

    @Override
    public void updateCard(Card card) {
        if (StringUtils.isBlank(card.getCardNo())) {
            throw new ServiceException("卡号不能为空");
        }

        // 绑定用户
        this.bindCardCustomer(card, false);

        cardMapper.updateById(card);
    }

    /**
     * 绑定卡用户
     *
     * @param card
     */
    private void bindCardCustomer(Card card, boolean add) {
        if (StringUtils.isNotEmpty(card.getMobile())) {
            Map<String, Object> param = Maps.newHashMap();
            param.put("MOBILE", card.getMobile());
            List<Customer> customerList = customerMapper.selectByMap(param);

            if (CollectionUtils.isEmpty(customerList)) {
                throw new ServiceException("手机号不存在");
            }

            card.setOpenId(customerList.get(0).getWeiXinOpenId());

            // 新增
            if (add) {
                // 启用卡
                card.setState(Constant.CARD_STATE_NORMAL);
                // 绑定时间
                card.setBindTime(new Date());
            } else {
                // 编辑

                Card card1 = cardService.selectByCardNo(card.getCardNo());
                if (Objects.isNull(card1)) {
                    throw new ServiceException("卡号不存在");
                }

                if (card1.getState().equals(Constant.CARD_STATE_LOSE)) {
                    throw new ServiceException("挂失的卡,不可编辑");
                }

                if (card1.getState().equals(Constant.CARD_STATE_NOT_OPEN)) {
                    // 启用卡
                    card.setState(Constant.CARD_STATE_NORMAL);
                    // 绑定时间
                    card.setBindTime(new Date());
                }
            }
        }
    }

    @Override
    /**
     *@描述 获取充值记录
     *@参数 [page, params 查询参数]
     *@返回值 com.baomidou.mybatisplus.core.metadata.IPage<com.dkm.modules.wx.card.model.RechargeRecods>
     *@创建人 yangbin
     *@创建时间 2019/10/6
     */
    //@DataScope(selfSql = "a.cardId in(select card_no from c_card where operator={})",customSql = "a.cardId in(select card_no from c_card where operator in {})")
    public IPage<RechargeRecods> geRechargeRecods(Map<String, Object> params, Page<RechargeRecods> page) {
        /*查询充值记录*/
        List<RechargeRecods> Recods = cardMapper.geRechargeRecods(page, params);
        /*组装使用记录为page类型*/
        page.setRecords(Recods);
        return page;
    }

    @Override
    /**
     *@描述 获取使用用户的数据列表
     *@参数 [params, page]
     *@返回值 com.baomidou.mybatisplus.core.metadata.IPage<com.dkm.modules.wx.user.model.UserData>
     *@创建人 yangbin
     *@创建时间 2019/10/19
     */
    public IPage<UserData> getUserList(Map<String, Object> params, Page<UserData> page) {
        List<UserData> userData = cardMapper.getUserList(params, page);
        page.setRecords(userData);
        return page;
    }

    @Override
    /**
     *@描述 注册用户列表
     *@参数 [params, page]
     *@返回值 com.baomidou.mybatisplus.core.metadata.IPage<com.dkm.modules.sys.user.model.RegisterUserResult>
     *@创建人 yangbin
     *@创建时间 2019/11/7
     */
    public IPage<RegisterUserResult> getRegisterUser(Map<String, Object> params, Page<RegisterUserResult> page) {
        List<RegisterUserResult> userData = cardMapper.getRegisterUser(params, page);
        page.setRecords(userData);
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transferAccounts(String openId, String cardNo, BigDecimal amount, User user) {

        // 校验
        if (Objects.isNull(openId) || StringUtils.isBlank(cardNo) || Objects.isNull(amount)) {
            throw new ServiceException("入参不能为空");
        }

        Card cardInfo = cardMapper.getCardInfo(cardNo);

        this.validatedWhenTransferAccounts(openId, cardInfo, amount);

        String batchNo = IdGen.uuid();

        // 转账
        // 账户金额扣减
        customerBalanceService.updateUserBalanceAndRecord(openId,
                amount.negate(),
                batchNo,
                Constant.RECHARGE_RECOD_TYPE_TRANSFER_ACCOUNTS,
                user
        );

        // 卡金额累加
        cardService.updateAmountAndRecord(cardNo, amount, batchNo, Constant.RECHARGE_RECOD_TYPE_TRANSFER_ACCOUNTS, user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAmountAndRecord(String cardNo, BigDecimal amount, String batchNo, Integer changeType, User user) {
        if (StringUtils.isBlank(cardNo)
                || amount == null
                || BigDecimal.ZERO.compareTo(amount) == 0
                || Objects.isNull(user)) {
            throw new ServiceException("更新卡余额,卡号,余额,操作人不能为空");
        }

        Card card = this.selectByCardNo(cardNo);

        this.validatedWhenUpdateAmount(amount, card);

        cardMapper.updateSumByCardNo(cardNo, amount);

        // 充值记录
        RechargeRecodPO recodPO = RechargeRecodPO.builder()
                .cardId(card.getId())
                .type(changeType)
                .dataType(1)
                .quantity(amount)
                .rechargeNumber(batchNo)
                .status(1)
                .openId(card.getOpenId())
                .createBy(user.getId())
                .createTime(new Date())
                .build();

        // 记录变更记录
        rechargeRecodMapper.insert(recodPO);
        log.info("更新卡:{}的余额:{}", cardNo, amount);
    }

    /**
     * 更新卡余额是校验
     *
     * @param amount
     * @param card
     */
    private void validatedWhenUpdateAmount(BigDecimal amount, Card card) {
        if (Objects.isNull(card)) {
            throw new ServiceException("卡号不存在");
        }

        if (BigDecimal.ZERO.compareTo(amount) == 1 && amount.abs().compareTo(card.getSum()) == 1) {
            throw new ServiceException("退款金额不能大于卡余额");
        }
        if (Constant.CARD_STATE_LOSE.equals(card.getCardNo())) {
            throw new ServiceException("挂失的卡不允许操作");
        }
    }

    @Override
    public Card selectByCardNo(String cardNo) {
        if (StringUtils.isBlank(cardNo)) {
            throw new ServiceException("根据卡号查询卡信息,卡号不能为空");
        }
        Map<String, Object> cardParam = Maps.newHashMap();
        cardParam.put("card_no", cardNo);
        List<Card> cards = cardMapper.selectByMap(cardParam);
        if (CollectionUtils.isEmpty(cards)) {
            return null;
        }
        return cards.get(0);
    }

    @Override
    public Card selectById(Integer id) {
        if (Objects.isNull(id)) {
            return null;
        }
        HashMap<String, Object> param = Maps.newHashMap();
        param.put("id", id);
        List<Card> cards = cardMapper.selectByMap(param);
        if (CollectionUtils.isEmpty(cards)) {
            return null;
        }
        return cards.get(0);
    }

    @Override
    public List<Card> getCardsByCustomerId(Integer customerId) {
        Customer customer = customerMapper.selectById(customerId);
        if (Objects.isNull(customer)) {
            return Lists.newArrayList();
        }

        Map<String, Object> param = Maps.newHashMap();
        param.put("open_id", customer.getWeiXinOpenId());

        List<Card> cards = cardMapper.selectByMap(param);
        if (CollectionUtils.isEmpty(cards)) {
            return Lists.newArrayList();
        }

        // 过滤
        cards = cards.stream()
                .filter(card -> !Constant.CARD_STATE_LOSE.equals(card.getState()))
                .collect(Collectors.toList());

        return cards;
    }

    private void validatedWhenTransferAccounts(String openid, Card cardInfo, BigDecimal amount) {
        if (BigDecimal.ZERO.compareTo(amount) >= 0) {
            throw new ServiceException("金额不能为0或负数");
        }

        CustomerBalance balance = customerBalanceService.selectByOpenId(openid);
        if (Objects.isNull(balance)) {
            throw new ServiceException("用户没有余额");
        }

        BigDecimal decimal = balance.getAmount();
        if (amount.compareTo(decimal) == 1) {
            throw new ServiceException("账户余额不足");
        }

        if (Objects.isNull(cardInfo)) {
            throw new ServiceException("卡号不存在");
        }
        if (!Objects.equals(cardInfo.getOpenId(), openid)) {
            throw new ServiceException("此卡不属于此用户");
        }
    }
}